package com.stock.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.stock.constant.StockConstant;
import com.stock.domain.vo.request.LoginRequest;
import com.stock.domain.vo.response.LoginResponse;
import com.stock.domain.vo.response.Response;
import com.stock.domain.vo.response.ResponseCode;
import com.stock.service.UserService;
import com.stock.mapper.SysUserMapper;
import com.stock.pojo.entity.SysUser;
import com.stock.utils.IdWorker;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service("userService")
public class UserServiceImpl implements UserService {
    //dao层
    @Autowired
    private SysUserMapper sysUserMapper;

    //加密器
    @Autowired
    private PasswordEncoder passwordEncoder;

    //序列化器
    @Autowired
    private RedisTemplate redisTemplate;

    //雪花算法--保证唯一id
    @Autowired
    private IdWorker idWorker;


    //TODO：根据用户名称查询用户信息
    @Override
    public SysUser selectByUsername(String username) {
        return sysUserMapper.selectByUsername(username);
    }

    //TODO：用户登录
    @Override
    public Response<LoginResponse> login(LoginRequest loginRequest) {
        //判断参数合法性
        /*  TODO：StringUtils工具类
         *          isBlank方法：判断字符串是否为空，为空返回true
         */
        if (loginRequest == null || StringUtils.isBlank(loginRequest.getUsername()) || StringUtils.isBlank(loginRequest.getPassword())) {
            return Response.error(ResponseCode.USERNAME_OR_PASSWORD_NULL);
        }

        //判断验证码和sessionId是否有效
        if (StringUtils.isBlank(loginRequest.getSessionId()) || StringUtils.isBlank(loginRequest.getCode())) {
            return Response.error(ResponseCode.CHECK_CODE_TIMEOUT);
        }

        //从缓存中获取验证码
        String rCode = (String) redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + loginRequest.getSessionId());
        //判断获取的验证码是否存在，以及是否与输入的验证码相同（忽略大小写）
        if (StringUtils.isBlank(rCode) || !rCode.equalsIgnoreCase(loginRequest.getCode())) {
            //验证码不存在或输入的验证码不正确
            return Response.error(ResponseCode.CHECK_CODE_ERROR);
        }

        //根据用户名查询用户信息
        SysUser sysUser = this.sysUserMapper.selectByUsername(loginRequest.getUsername());
        //判断用户是否存在，存在则进行密码校验
        if (sysUser == null || !passwordEncoder.matches(loginRequest.getPassword(), sysUser.getPassword())) {
            return Response.error(ResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }

        //到这里没有返回，说明密码正确
        //准备返回给页面的成功数据
        LoginResponse loginResponse = new LoginResponse();
        /*
         *  TODO：BeanUtils工具类
         *      copyProperties方法：（相当于set方法）
         *         将sysUser和loginResponse中相同的属性名称和类型，封装给loginResponse
         */
        BeanUtils.copyProperties(sysUser, loginResponse);

        //将封装好的数据，进行返回
        return Response.ok(loginResponse);
    }

    //TODO：登录验证码功能实现
    @Override
    public Response<Map> getCaptchaCode() {
        //设置验证码图片为长方形，宽为250，高40，验证码长度4位，干扰线5条
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(250, 40, 4, 5);
        //设置验证码图片背景颜色为清灰色
        captcha.setBackground(Color.lightGray);
        //获取验证码
        String code = captcha.getCode();
        System.out.println("验证码为：" + code);
        //生成sessionId--并转成String类型，防止失真
        String sessionId = String.valueOf(idWorker.nextId());
        //将sessionId和校验码保存在redis下，并设置缓存中数据存活时间一分钟
        //CHECK_PREFIX的作用：在Redis中把这个key-value数据标识为验证码，方便后期统计数量
        redisTemplate.opsForValue().set(StockConstant.CHECK_PREFIX + sessionId, code, 1, TimeUnit.MINUTES);
        //组装响应数据
        HashMap<String, String> info = new HashMap<>();
        info.put("sessionId", sessionId);   //sessionId验证码的key
        info.put("imageData", captcha.getImageBase64());
        //设置响应数据格式
        return Response.ok(info);
    }
}
